package com.shadow.demo.info.service;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shadow.demo.common.bo.ResultInfo;
import com.shadow.demo.common.constants.SysConstants;
import com.shadow.demo.common.info.InfoConstants;
import com.shadow.demo.common.util.HttpUtils;
import com.shadow.demo.common.util.ip.IPUtils;
import com.shadow.demo.data.info.entity.IpInfoEntity;
import com.shadow.demo.data.info.mapper.IpInfoMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Calendar;
import java.util.Date;
import java.util.Objects;
import java.util.Set;

@Slf4j
@DS("info")
@Service
public class IpInfoService extends ServiceImpl<IpInfoMapper, IpInfoEntity> {

    @Resource
    private IpInfoMapper ipInfoMapper;

    @Value("${ip.enable}")
    private Boolean ipEnable;

    /* 清理数据时保留的最大条数 */
    private static final int CLEAR_NUM = 5;

    private static final String PUBLIC_IP_URL = "https://icanhazip.com/";
    private static final String PUBLIC_PRE = "public-";

    public void register(final String type, final String localHostName, final String ip) {
        log.info("execute type : {}", type);
        IpInfoEntity latestData = getLatestData(type, ip);
        Date now = Calendar.getInstance().getTime();
        if (Objects.isNull(latestData)) {
            IpInfoEntity ipInfoEntity = new IpInfoEntity()
                    .setType(type)
                    .setMachineName(localHostName)
                    .setIpAddress(ip)
                    .setAddDate(now)
                    .setUpdateDate(now)
                    .setSum(1);
            log.info("Insert IP : {}", ipInfoEntity.getIpAddress());
            ipInfoMapper.insert(ipInfoEntity);
            return;
        }
        latestData.setSum(latestData.getSum() + 1)
                .setUpdateDate(now);
        ipInfoMapper.updateById(latestData);
        log.info("Update IP : {}", latestData.getIpAddress());
    }

    /**
     * 获取公网ip
     */
    public String getPublicIp1() {
        ResultInfo resultInfo = HttpUtils.sendGet(PUBLIC_IP_URL, null);
        if (resultInfo.isResult()) {
            String localHostName = IPUtils.getLocalHostName();
            IpInfoEntity ipInfoEntity = new IpInfoEntity();
            ipInfoEntity.setType(PUBLIC_PRE + localHostName)
                    .setMachineName(localHostName)
                    .setIpAddress((resultInfo.getData() + StringUtils.EMPTY).replace("\n", StringUtils.EMPTY))
                    .setAddDate(new Date());
            ipInfoMapper.insert(ipInfoEntity);
            return ipInfoEntity.getIpAddress();
        }
        return StringUtils.EMPTY;
    }

    @Scheduled(cron = "${ip.clear}")
    public void clearIp() {
        if (log.isDebugEnabled()) {
            log.debug("start clear ip. {}", ipEnable);
        }
        if (Boolean.FALSE.equals(ipEnable)) {
            return;
        }
        Set<String> allType = getAllType();
        if (CollectionUtils.isNotEmpty(allType)) {
            allType.forEach(this::clearByType);
        }
        if (log.isDebugEnabled()) {
            log.debug("end clear ip.");
        }
    }

    /**
     * 获取最新的IP信息
     * */
    public IpInfoEntity getLatestData(final String type, final String ip) {
        LambdaQueryWrapper<IpInfoEntity> wrapper = new LambdaQueryWrapper<IpInfoEntity>()
                .eq(StringUtils.isNotEmpty(type), IpInfoEntity::getType, type)
                .eq(StringUtils.isNotEmpty(ip), IpInfoEntity::getIpAddress, ip)
                .orderByDesc(IpInfoEntity::getUpdateDate)
                .last("limit 1");
        return ipInfoMapper.selectOne(wrapper);
    }

    /**
     * 所有类型
     */
    public Set<String> getAllType() {
        return ipInfoMapper.getAllType();
    }

    /**
     * 按照类型进行清理
     * */
    public void clearByType(final String type) {
        if (StringUtils.isEmpty(type)) {
            return;
        }
        int delete = ipInfoMapper.clearByType(type, CLEAR_NUM);
        log.info("ip cleared type : {}, count : {}", type, delete);
    }
}
